#include "MessageDispatcher.h"
#include "Message.h"
#include "MessageListener.h"

MessageDispatcher::~MessageDispatcher()
{
}

MessageListener*
MessageDispatcher::getListener(const string &msgCode) const
{
    ListenerMap::const_iterator it = m_listener.find(msgCode);
    if (it != m_listener.end())
        return it->second.front();
    return nullptr;
}

void
MessageDispatcher::subscribe(const string &msgCode, MessageListener* listener)
{
    if (not msgCode.empty()) {
        vector<string> codes = split<string>(msgCode, ",");
        foreach (const string &code, codes) {
            m_listener[code].push_front(listener);
        }
    }
    else {
        m_catchAllListeners.push_front(listener);
    }
}

void
MessageDispatcher::unsubscribe(const string &msgCode, MessageListener* listener)
{

    if (!msgCode.empty()) {
        vector<string> codes = split<string>(msgCode, ",");
        foreach (const string &code, codes) {
            ListenerMap::iterator it = m_listener.find(code);
            if (it != m_listener.end()) {
                it->second.remove(listener);
                if (it->second.empty()) {
                    m_listener.erase(code);
                }
            }
            else {
                qWarning() << "No listener listens for code " << code.c_str();
            }
        }
    }
    else {
        m_catchAllListeners.remove(listener);
    }

    m_listener[msgCode].remove(listener);
    if (m_listener[msgCode].empty()) {
        m_listener.erase(msgCode);
    }
}

void
MessageDispatcher::dispatch(const Message &msg)
{
    bool hasToSignal = false;
    ListenerMap::const_iterator it = m_listener.find(msg.code());
    if (it != m_listener.end()) {
        it->second.front()->receive(msg);
        hasToSignal = true;
    }
    else {
        for (ListenerList::iterator i = m_catchAllListeners.begin(); i != m_catchAllListeners.end(); ++i) {
            if ((*i)->receive(msg)) {
                hasToSignal = true;
                break;
            }
        }
    }

    if (hasToSignal) {
        dispatched(msg);
    }
}

